package org.jeecg.modules.appUser;

import com.alibaba.fastjson.JSONArray;
import com.aliyuncs.exceptions.ClientException;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.modules.app.userSetting.entity.AppUserSetting;
import org.jeecg.modules.app.userSetting.service.AppUserSettingService;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.message.entity.SysMessageTemplate;
import org.jeecg.modules.message.service.ISysMessageTemplateService;
import org.jeecg.modules.system.entity.SysFiles;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.*;
import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.utils.WeChatUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @description: APP LOGIN API
 * @author: zwf
 * @create: 2025-06-13 10:43
 **/
@Slf4j
@Tag(name = "用户登录")
@RequestMapping("/app")
@RestController
public class AppLoginController {
    @Value("${config.applet.sso}")
    private String sso;
    @Value("${config.applet.appId}")
    private String appId;
    @Value("${config.applet.appSecret}")
    private String appSecret;

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private AppUserSettingService userSettingService;
    @Resource
    private SysBaseApiImpl sysBaseApi;
    @Resource
    private BaseCommonService baseCommonService;
    @Resource
    private ISysMessageTemplateService templateService;
    @Resource
    private CommonAPI commonApi;
    @Resource
    private ShiroRealm shiroRealm;
    @Resource
    private ISysFilesService filesService;


    @PostMapping("/beforeLogin")
    @Operation(summary = "预登录")
    public Result<String> beforeLogin(@RequestBody JSONObject params) {
        return userSettingService.beforeLogin(params);
    }


    /**
     * app用户登录
     *
     * @author zwf
     * @date created in 2025-06-13 11:39
     * @param: sysLoginModel
     * @param: request
     * @return: org.jeecg.common.api.vo.Result<com.alibaba.fastjson.JSONObject>
     */
    @Operation(summary = "登录接口")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        if (isLoginFailOvertimes(username)) {
            return result.error500("该用户登录失败次数过多，请于10分钟后再次登录！");
        }
        // step.1 校验用户是否存在且有效
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserService.getOne(queryWrapper);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }
        // step.2 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            addLoginFailOvertimes(username);
            result.error500("用户名或密码错误");
            return result;
        }
        if (sysLoginModel.getCaptcha() != null && !"ECHO-REMINIS-H5".equals(sysLoginModel.getCaptcha())) {
            // 微信id与用户绑定 获取openid
            JSONObject weChatSession = WeChatUtil.getWeChatSession(sso, appId, appSecret, sysLoginModel.getCaptcha());
            if (!weChatSession.isEmpty() && weChatSession.containsKey("openid")) {
                // 获取用户设置
                AppUserSetting userSetting = userSettingService.getByOpenId(weChatSession.getString("openid"));

                if (userSetting != null) {
                    // 同步设置
                    Boolean setNotPrimary = userSettingService.updateUserPrimary(sysUser.getId(), userSetting);
                    if (setNotPrimary) {
                        // 设置所有主账号为非主账号
                        userSettingService.setNotPrimary(sysUser.getId());
                        userSetting.setUserId(sysUser.getId());
                        userSetting.setUpdateBy(sysUser.getId());
                        userSetting.setUpdateTime(new Date());
                        // 设置当前登录用户为主用户
                        userSetting.setIsPrimary("1");

                        userSettingService.updateById(userSetting);
                    } else {
                        result.error500("账号同步失败");
                        return result;
                    }
                } else {
                    JSONObject params = new JSONObject();

                    params.put("code", sysLoginModel.getCaptcha());
                    params.put("userId", sysUser.getId());

                    Result<String> beforeLoginResult = userSettingService.beforeLogin(params);
                    if (!beforeLoginResult.isSuccess()) {
                        result.error500(beforeLoginResult.getMessage());
                        return result;
                    }
                }

            } else {
                result.error500("微信登录异常");
                return result;
            }
        }
        // step.3  登录成功获取用户信息
        userInfo(sysUser, result, request);
        // step.4  登录成功删除验证码
        redisUtil.del(CommonConstant.LOGIN_FAIL + username);
        // step.5  记录用户登录日志
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        return result;
    }

    @PostMapping("/updateUserInfo")
    @Operation(summary = "修改用户信息")
    public Result<String> updateUserInfo(@RequestBody JSONObject params) {
        log.info("参数：{}", params);
        return userSettingService.updateUserInfo(params);
    }

    @PostMapping("/uploadAvatar")
    @Operation(summary = "上传头像")
    public Result<String> uploadAvatar(@RequestParam("file") MultipartFile file) {
        return userSettingService.uploadAvatar(file);
    }

    /**
     * 判断登录失败次数是否超过5次
     *
     * @author zwf
     * @date created in 2025-06-13 11:39
     * @param: username
     * @return: boolean
     */
    private boolean isLoginFailOvertimes(String username) {
        String key = CommonConstant.LOGIN_FAIL + username;
        Object failTime = redisUtil.get(key);
        if (failTime != null) {
            Integer val = Integer.parseInt(failTime.toString());
            if (val > 5) {
                return true;
            }
        }
        return false;
    }

    /**
     * 记录登录失败次数
     *
     * @author zwf
     * @date created in 2025-06-13 11:39
     * @param: username
     */
    private void addLoginFailOvertimes(String username) {
        String key = CommonConstant.LOGIN_FAIL + username;
        Object failTime = redisUtil.get(key);
        Integer val = 0;
        if (failTime != null) {
            val = Integer.parseInt(failTime.toString());
        }
        // 10分钟，一分钟为60s
        redisUtil.set(key, ++val, 600);
    }

    /**
     * 封装登录成功后的用户信息
     *
     * @author zwf
     * @date created in 2025-06-13 11:38
     * @param: sysUser
     * @param: result
     * @param: request
     * @return: org.jeecg.common.api.vo.Result<com.alibaba.fastjson.JSONObject>
     */
    private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result, HttpServletRequest request) {
        JSONObject userInfo = new JSONObject(new LinkedHashMap<>());

        String username = sysUser.getUsername();
        String syspassword = sysUser.getPassword();
        //1.生成token
        String token = JwtUtil.sign(username, syspassword);
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        userInfo.put("token", token);
        //3.设置登录用户信息
        userInfo.put("userInfo", packeageUserInfo(sysUser));

        result.setResult(userInfo);
        result.success("登录成功");
        return result;
    }

    /**
     * 封装登录成功后的用户信息
     *
     * @author zwf
     * @date created in 2025-06-13 11:38
     * @param: sysUser
     * @return: com.alibaba.fastjson.JSONObject
     */
    private JSONObject packeageUserInfo(SysUser sysUser) {
        JSONObject result = new JSONObject();

        AppUserSetting userSetting = userSettingService.getByUserId(sysUser.getId());

        result.put("id", sysUser.getId());
        result.put("username", sysUser.getUsername());
        result.put("realname", sysUser.getRealname());
        result.put("avatar", sysUser.getAvatar());
        result.put("sex", sysUser.getSex());
        result.put("birthday", sysUser.getBirthday());
        // 是否会员
        result.put("userIdentity", sysUser.getUserIdentity());
        result.put("phone", sysUser.getPhone());
        result.put("email", sysUser.getEmail());
        // app相关数据
        JSONObject setting = new JSONObject();
        if (userSetting != null) {
            setting.put("remindType", userSetting.getRemindType());
            setting.put("plateNumber", userSetting.getPlateNumber());
            setting.put("remindCount", userSetting.getRemindCount());
            setting.put("accountCount", userSetting.getAccountCount());
            setting.put("memoCount", userSetting.getMemoCount());
        }
        // 挪车码地址
        LambdaQueryWrapper<SysFiles> query = new LambdaQueryWrapper<>();
        query.eq(SysFiles::getCreateBy, sysUser.getId());
        query.eq(SysFiles::getDelFlag, "0");
        query.eq(SysFiles::getStoreType, "app-move");

        SysFiles file = filesService.getOne(query);
        if (file != null) {
            setting.put("oneKeyMoveUrl", file.getUrl());
        }
        // 轮播图信息
        query = new LambdaQueryWrapper<>();

        query.eq(SysFiles::getStoreType, "app-home-swiper");
        query.eq(SysFiles::getDelFlag, "0");

        List<SysFiles> swiperList = filesService.list(query);

        if (swiperList != null && !swiperList.isEmpty()) {
            JSONArray homeSwipers = new JSONArray();
            swiperList.forEach(item -> {
                homeSwipers.add(item.getUrl());
            });
            setting.put("homeSwipers", homeSwipers);
        }

        result.put("setting", setting);

        return result;
    }

    /**
     * 退出登录
     *
     * @author zwf
     * @date created in 2025-06-13 11:38
     * @param: request
     * @param: response
     * @return: org.jeecg.common.api.vo.Result<java.lang.Object>
     */
    @RequestMapping(value = "/logout")
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        LoginUser sysUser = sysBaseApi.getUserByName(username);
        if (sysUser != null) {
            //update-begin--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            baseCommonService.addLog("用户名: " + sysUser.getRealname() + ",退出成功！", CommonConstant.LOG_TYPE_1, null, sysUser);
            //update-end--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            log.info(" 用户名:  " + sysUser.getRealname() + ",退出成功！ ");
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
            //调用shiro的logout
            SecurityUtils.getSubject().logout();
            return Result.ok("退出登录成功！");
        } else {
            return Result.error("Token无效!");
        }
    }

    /**
     * 刷新token
     *
     * @author zwf
     * @date created in 2025-06-13 11:38
     * @param: request
     * @return: org.jeecg.common.api.vo.Result
     */
    @Operation(summary = "刷新token")
    @GetMapping("/refreshToken")
    public Result refreshToken(HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isEmpty(token)) {
            return Result.error("Token不能为空!");
        }
        String username = JwtUtil.getUsername(token);
        if (username == null) {
            return Result.error("Token无效!");
        }
        LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil);
        if (loginUser == null) {
            return Result.error("用户不存在!");
        }
        if (loginUser.getStatus() != 1) {
            return Result.error("账号已被锁定,请联系管理员!");
        }
        boolean refreshed = shiroRealm.jwtTokenRefresh(token, username, loginUser.getPassword());
        if (refreshed) {
            String newToken = (String) redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token);
            return Result.OK("刷新成功", newToken);
        } else {
            return Result.error("Token已失效，请重新登录!");
        }
    }


    /**
     * 验证码相关
     *
     * @author zwf
     * @date created in 2025/4/28 15:55
     * @param: phoneNumber
     * @param: model   0 .登录模板、1.注册模板、2.忘记密码模板
     * @return: org.jeecg.common.api.vo.Result<java.lang.String>
     */
    @GetMapping(value = "/verifyCode")
    public Result<String> verifyCode(@RequestParam(name = "phoneNumber", required = true) String phoneNumber, @RequestParam(name = "model", required = true) String model) {
        Result<String> result = new Result<String>();

        log.info(phoneNumber);

        if (oConvertUtils.isEmpty(phoneNumber)) {
            result.setMessage("手机号码不允许为空！");
            result.setSuccess(false);
            return result;
        }
        String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE + phoneNumber;

        Object object = redisUtil.get(redisKey);

        if (object != null) {
            result.setMessage("验证码10分钟内，仍然有效！");
            result.setSuccess(false);
            return result;
        }

        //随机数
        String captcha = RandomUtil.randomNumbers(6);

        JSONObject obj = new JSONObject();

        obj.put("code", captcha);

        try {
            boolean b = false;
            //注册
            if (CommonConstant.SMS_TPL_TYPE_1.equals(model)) {
                SysUser sysUser = sysUserService.getUserByPhone(phoneNumber);
                if (sysUser != null) {
                    result.error500("该手机号码已经注册，请直接登录！");
                    baseCommonService.addLog("该手机号码已经注册，请直接登录！", CommonConstant.LOG_TYPE_1, null);
                    return result;
                }
                SysMessageTemplate template = getMessageTemplate("sms-register");

                if (template != null) {
                    b = DySmsHelper.sendMessage(phoneNumber, obj, JSONObject.parseObject(template.getTemplateContent())).isSuccess();
                }
            } else {
                //登录模式，校验用户有效性
                SysUser sysUser = sysUserService.getUserByPhone(phoneNumber);
                result = sysUserService.checkUserIsEffective(sysUser);
                if (!result.isSuccess()) {
                    String message = result.getMessage();
                    String userNotExist = "该用户不存在，请注册";
                    if (userNotExist.equals(message)) {
                        result.error500("该用户不存在或未绑定手机号");
                    }
                    return result;
                }

                /**
                 * model 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                 */
                if (CommonConstant.SMS_TPL_TYPE_0.equals(model)) {
                    //登录模板
                    SysMessageTemplate template = getMessageTemplate("sms-login");

                    if (template != null) {
                        b = DySmsHelper.sendMessage(phoneNumber, obj, JSONObject.parseObject(template.getTemplateContent())).isSuccess();
                    }
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(model)) {
                    //忘记密码模板
                    SysMessageTemplate template = getMessageTemplate("sms-passwd");

                    if (template != null) {
                        b = DySmsHelper.sendMessage(phoneNumber, obj, JSONObject.parseObject(template.getTemplateContent())).isSuccess();
                    }
                }
            }

            if (b == false) {
                result.setMessage("短信验证码发送失败,请稍后重试");
                result.setSuccess(false);
                return result;
            }

            //验证码10分钟内有效
            redisUtil.set(redisKey, captcha, 600);
            result.setSuccess(true);

        } catch (ClientException e) {
            e.printStackTrace();
            result.error500(" 短信接口未配置，请联系管理员！");
            return result;
        }
        return result;
    }

    private SysMessageTemplate getMessageTemplate(String model) {
        List<SysMessageTemplate> templates = templateService.selectByCode(model);

        SysMessageTemplate template;

        if (templates != null && templates.size() > 0) {
            template = templates.get(0);
            return template;
        } else {
            return null;
        }
    }

    /**
     * 邮箱
     *
     * @author zwf
     * @date created in 2025/4/28 15:55
     * @param: phoneNumber
     * @param: model   0 .登录模板、1.注册模板、2.忘记密码模板
     * @return: org.jeecg.common.api.vo.Result<java.lang.String>
     */
    @GetMapping(value = "/verifyCodeEmail")
    public Result<String> verifyCodeEmail(@RequestParam(name = "email", required = true) String email, @RequestParam(name = "model", required = true) String model) {
        Result<String> result = new Result<String>();

        log.info(email);

        if (oConvertUtils.isEmpty(email)) {
            result.setMessage("邮箱不允许为空！");
            result.setSuccess(false);
            return result;
        }
        String redisKey = CommonConstant.EMAIL_REDIS_KEY_PRE + email;

        Object object = redisUtil.get(redisKey);

        if (object != null) {
            result.setMessage("验证码10分钟内，仍然有效！");
            result.setSuccess(false);
            return result;
        }

        //随机数
        String captcha = RandomUtil.randomNumbers(6);

        JSONObject obj = new JSONObject();

        obj.put("code", captcha);

        try {
            boolean b = false;
            //注册
            if (CommonConstant.SMS_TPL_TYPE_1.equals(model)) {
                SysUser sysUser = sysUserService.getUserByEmail(email);
                if (sysUser != null) {
                    result.error500("该邮箱已经注册，请直接登录！");
                    baseCommonService.addLog("该邮箱已经注册，请直接登录！", CommonConstant.LOG_TYPE_1, null);
                    return result;
                }
                b = templateService.sendEmailSms(email, obj, "email-register");
            } else {
                //登录模式，校验用户有效性
                SysUser sysUser = sysUserService.getUserByEmail(email);
                result = sysUserService.checkUserIsEffective(sysUser);
                if (!result.isSuccess()) {
                    String message = result.getMessage();
                    String userNotExist = "该用户不存在，请注册";
                    if (userNotExist.equals(message)) {
                        result.error500("该用户不存在或未绑定邮箱");
                    }
                    return result;
                }

                /**
                 * model 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                 */
                if (CommonConstant.SMS_TPL_TYPE_0.equals(model)) {
                    //登录模板
                    b = templateService.sendEmailSms(email, obj, "email-login");
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(model)) {
                    //忘记密码模板
                    b = templateService.sendEmailSms(email, obj, "email-passwd");
                }
            }

            if (b == false) {
                result.setMessage("邮箱验证码发送失败,请稍后重试");
                result.setSuccess(false);
                return result;
            }

            //验证码10分钟内有效
            redisUtil.set(redisKey, captcha, 600);
            result.setSuccess(true);

        } catch (Exception e) {
            e.printStackTrace();
            result.error500(" 邮箱接口未配置，请联系管理员！");
            return result;
        }
        return result;
    }
}
